#!/usr/bin/env python3

import os
import shutil

import common

class LinuxComponent(common.Component):
    def add_parser_arguments(self, parser):
        parser.add_argument(
            '--config', default=[], action='append',
            help='''\
Add a single kernel config configs to the current build. Sample value:
'CONFIG_FORTIFY_SOURCE=y'. Can be used multiple times to add multiple
configs. Takes precedence over any config files.
'''
        )
        parser.add_argument(
            '--config-fragment', default=[], action='append',
            help='''\
Also use the given kernel configuration fragment file.
Pass multiple times to use multiple fragment files.
'''
        )
        parser.add_argument(
            '--custom-config-file',
            help='''\
Ignore all default kernel configurations and use this file instead.
Still uses options explicitly passed with `--config` and
`--config-fragment` on top of it.
'''
        )
        parser.add_argument(
            '--config-only', default=False, action='store_true',
            help='''\
Configure the kernel, but don't build it.
'''
        )
        parser.add_argument(
            '--initramfs', default=False, action='store_true',
        )
        parser.add_argument(
            '--initrd', default=False, action='store_true',
        )
        parser.add_argument(
            'extra_make_args',
            default=[],
            metavar='extra-make-args',
            nargs='*'
        )

    def do_build(self, args):
        build_dir = self.get_build_dir(args)
        if args.initrd or args.initramfs:
            raise Exception('just trolling, --initrd and --initramfs are broken for now')
        os.makedirs(build_dir, exist_ok=True)
        tool = 'gcc'
        gcc = common.get_toolchain_tool(tool)
        prefix = gcc[:-len(tool)]
        common_args = {
            'cwd': common.linux_src_dir,
        }
        ccache = shutil.which('ccache')
        if ccache is not None:
            cc = '{} {}'.format(ccache, gcc)
        else:
            cc = gcc
        common_make_args = [
            'make',
            '-j', str(args.nproc),
            'ARCH={}'.format(common.linux_arch),
            'CROSS_COMPILE={}'.format(prefix),
            'CC={}'.format(cc),
            'O={}'.format(build_dir),
        ]
        if args.verbose:
            verbose = ['V=1']
        else:
            verbose = []
        if args.custom_config_file is not None:
            if not os.path.exists(args.custom_config_file):
                raise Exception('config fragment file does not exist: {}'.format(args.custom_config_file))
            base_config_file = args.custom_config_file
            config_fragments = []
        else:
            base_config_file = os.path.join(common.linux_config_dir, 'buildroot-{}'.format(args.arch))
            config_fragments = ['min', 'default']
            for i, config_fragment in enumerate(config_fragments):
                config_fragments[i] = os.path.join(common.linux_config_dir, config_fragment)
        config_fragments.extend(args.config_fragment)
        if args.config != []:
            cli_config_fragment_path = os.path.join(build_dir, 'lkmc_cli_config_fragment')
            cli_config_str = '\n'.join(args.config)
            common.write_string_to_file(cli_config_fragment_path, cli_config_str)
            config_fragments.append(cli_config_fragment_path)
        common.cp(
            base_config_file,
            os.path.join(build_dir, '.config'),
        )
        common.run_cmd(
            [
                os.path.join(common.linux_src_dir, 'scripts', 'kconfig', 'merge_config.sh'),
                '-m',
                '-O', build_dir,
                os.path.join(build_dir, '.config'),
            ] +
            config_fragments
        )
        common.run_cmd(
            (
                common_make_args +
                ['olddefconfig']
            ),
            **common_args
        )
        if not args.config_only:
            common.run_cmd(
                (
                    common_make_args +
                    args.extra_make_args
                ),
                **common_args
            )

    def get_argparse_args(self):
        return {
            'description': '''\
Build the Linux kernel.
'''
        }

    def get_build_dir(self, args):
        return common.linux_build_dir

if __name__ == '__main__':
    LinuxComponent().build()
